package service

import (
	"context"
	"golang.org/x/sync/errgroup"
	"time"
	"webook/article/domain"
	"webook/article/events"
	"webook/article/repository"
	"webook/pkg/logger"
)

type ArticleService interface {
	Save(ctx context.Context, art domain.Article) (int64, error)
	Publish(ctx context.Context, art domain.Article) (int64, error)
	Withdraw(ctx context.Context, uid, id int64) error
	List(ctx context.Context, author int64, offset, limit int) ([]domain.Article, error)
	GetById(ctx context.Context, id int64) (domain.Article, error)

	// GetPublishedById 查找已经发表的
	GetPublishedById(ctx context.Context, id, uid int64) (domain.Article, error)
	// ListPub 根据更新时间来分页，更新时间必须小于 startTime
	ListPub(ctx context.Context, startTime time.Time, offset, limit int) ([]domain.Article, error)
}

type articleService struct {
	userRepo repository.AuthorRepository
	repo     repository.ArticleRepository
	logger   logger.LoggerV1

	// 搞个异步的
	producer events.Producer
}

func NewArticleService(repo repository.ArticleRepository, authorRepo repository.AuthorRepository,
	l logger.LoggerV1, producer events.Producer) ArticleService {
	return &articleService{
		repo:     repo,
		logger:   l,
		userRepo: authorRepo,
		producer: producer,
	}
}

func (svc *articleService) Save(ctx context.Context, art domain.Article) (int64, error) {
	// 保存草稿，但是未发表
	art.Status = domain.ArticleStatusUnpublished
	if art.Id > 0 {
		err := svc.repo.Update(ctx, art)
		return art.Id, err
	}
	return svc.repo.Create(ctx, art)
}

func (svc *articleService) Publish(ctx context.Context, art domain.Article) (int64, error) {
	art.Status = domain.ArticleStatusPublished
	// 也可以像 Save 方法那样
	return svc.repo.Sync(ctx, art)
}

func (svc *articleService) Withdraw(ctx context.Context, uid, id int64) error {
	return svc.repo.SyncStatus(ctx, uid, id, domain.ArticleStatusPrivate)
}

func (svc *articleService) List(ctx context.Context, author int64, offset, limit int) ([]domain.Article, error) {
	return svc.repo.List(ctx, author, offset, limit)
}

func (svc *articleService) GetById(ctx context.Context, id int64) (domain.Article, error) {
	return svc.repo.GetById(ctx, id)
}

func (svc *articleService) GetPublishedById(ctx context.Context, id, uid int64) (domain.Article, error) {
	var eg errgroup.Group
	var art *domain.Article
	var author *domain.Author
	var err error
	eg.Go(func() error {
		res, err2 := svc.repo.GetPublishedById(ctx, id)
		art = &res
		return err2
	})

	eg.Go(func() error {
		res, err2 := svc.userRepo.FindAuthor(ctx, uid)
		author = &res
		return err2
	})

	if err = eg.Wait(); err != nil {
		return domain.Article{}, err
	}
	art.Author = *author
	res := *art
	go func() {
		if err == nil {
			er := svc.producer.ProduceReadEvent(events.ReadEvent{
				Aid: id,
				Uid: uid,
			})
			if er != nil {
				svc.logger.Error("发送消息失败",
					logger.Int64("uid", uid),
					logger.Int64("aid", id),
					logger.Error(err))
			}
		}
	}()
	return res, nil
}

func (svc *articleService) ListPub(ctx context.Context, startTime time.Time, offset, limit int) ([]domain.Article, error) {
	return svc.repo.ListPub(ctx, startTime, offset, limit)
}
